#ifndef __Memory_H_
#define __Memory_H_

#include <irrlicht.h>
#include <iostream>
#include <map>

#include "debug.h"
#include "Entity.h"
#include "Hostility.h"

class Hostility ;

/*! Class implementing simple memory for NPCs */
class Memory
{
	public:
	/*! the struct meminfo is used to store extra information about the entity */
	typedef struct
	{
        	/*! since the memroy has been added */
		float timeSinceSeen;
		/*! the type of entity which has been seen */
		irr::core::string<c8> type;
		/*! last known position of the entity */
		irr::core::vector3df position;
		/*! is the entity still here ? */
		bool stillExists ;
		
	} meminfo_t;

	protected:
        	/*! this is the list of all entities spotted and info related */
		std::map<Entity*,meminfo_t> mem__;
		/*! this is the time the bot will remember something */
		float forgetTime__;
		Hostility hostilities__ ;	/**< Hostility list of the Entity. */

	public:
		/*! empty constructor */
		Memory();
		/*! destructor */
		virtual ~Memory();

		/*! set the time before forgetting */
		void setForgetTime(float f);
		/*! returns the time before forgetting */
		float getForgetTime();

		/*! add a memory to the map using a pointer to an entity and the extra informations */
		void addMemory(Entity*,meminfo_t);
		/*! adds a memory with only entity using standard minimal meminfo */
		void addMemory(Entity*);
		/*! frame processor for memory, decreasing time before the bots forgets */
		void updateMemory(float elapsedtime);

		/*! returns the whole list of memories */
		std::map<Entity*, meminfo_t>& getMemory();
		/*! returns a sublist of the memories associated to a given type */
		std::map<Entity*, meminfo_t> getMemoryByType(irr::core::string<c8> type);
		/*! returns a sublist of the memories containing the attribute Eatable == 1 */
		std::map<Entity*, Memory::meminfo_t> getMemoryEatable();
		/*! returns a sublist of the memories containing the attribute Eatable == 1 for dead Entities*/
		std::map<Entity*, Memory::meminfo_t>getMemoryEatableDead();
		/*! returns a sublist of the memories associated to a given hostility (hostile, allied, feared, neutral) */
		std::map<Entity*, Memory::meminfo_t> getMemoryByHostility(Hostility::reaction_t reac);
		/*! return true if there is in the memory an entity with the hostily == reac, false else */
		bool isInMemoryHostility(Hostility::reaction_t reac);
		/*! return true if there is in the memory an entity with the type == reac, false else */
		bool isInMemoryType(irr::core::string<c8> type);
		/*! return true if there is in the memory an entity eatable, false else */
		bool isInMemoryEatable();
		/*! return true if there is in the memory an entity eatable dead, false else */
		bool isInMemoryEatableDead();
		/*! returns the nearest hostile */
		Entity * getNearestHostile(Entity * executer) ;
		/*! returns the whole memory of the nearest hostile */
		std::pair<Entity*, meminfo_t> getNearestHostilePair(Entity * executer) ;
		/*! returns the whole memory of a nearest enemy */
		std::pair<Entity*, Memory::meminfo_t> getNearestEnemyPair(Entity * executer);
		/*! returns the nearest pair of a given type */
		std::pair<Entity*, Memory::meminfo_t> getNearestPair(Entity * executer,irr::core::string<c8> type) ;
		/*! returns the whole memory of the nearest food piece */
		std::pair<Entity*, Memory::meminfo_t> getNearestFoodPair(Entity * executer) ;
		/*! returns the whole memory of the nearest food piece for dead entities*/
		std::pair<Entity*, Memory::meminfo_t> getNearestFoodPairDead(Entity * executer) ;

		/*! returns true if the memory is empty */ 
		bool isEmptyMemory(std::pair<Entity*, meminfo_t> mem) ;
		/*! make the memory forgettable */
		void timeToForget(Entity * obsolete) ;
		/*! returns the hostility list of the NPC. */
		virtual Hostility* getHostilities();
		/*! Affiche la memoir de l'entity qui appelle la fonction*/
		void memoryDisplay();
};		

#endif
